package serverComuncation;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;

import communicationMessages.Message;

import logger.LoggerWriter;

import data.ForumServer;





class ConnectionHandler2 implements Runnable {
	private BufferedReader in;
	private PrintWriter out;
	Socket clientSocket;
	ServerProtocol protocol;
	public ConnectionHandler2(Socket acceptedSocket, ServerProtocol p) {
		in = null;
		out = null;
		clientSocket = acceptedSocket;
		protocol = p;
		LoggerWriter logger = LoggerWriter.getLoggerWriter();
		logger.log("Accepted connection from client!",Level.INFO);
		logger.log("The client is from: " + 
				acceptedSocket.getInetAddress() + ":" + acceptedSocket.getPort(),Level.INFO);
	}
	public void run() {
		LoggerWriter logger = LoggerWriter.getLoggerWriter();
		try {
			initialize();
			Observer.observer.addNewOut(out,clientSocket.getLocalPort());
		} catch (IOException e) {
			logger.log("Error in initializing I/O",Level.INFO);
		}
		try {
			process();
		} catch (IOException e) {
			logger.log("Error in I/O",Level.INFO);
			Observer.observer.removeOut(out);
			System.out.println("i am finshed "  + out.toString());
		} 
		logger.log("Connection closed - bye bye...",Level.INFO);
		close();
	}

	public void process() throws IOException {
		String msg;
		msg = readMsg();
		while (msg != null  && !protocol.isEnd(msg) && !msg.equals("") ) {
			LoggerWriter logger = LoggerWriter.getLoggerWriter();
			logger.log("Received \"" + msg + "\" from client", Level.INFO);
			String response = protocol.processMessage(msg);
			if (response != null) {
				logger.log("the response "+response, Level.INFO);
				out.println(response);
			}
			msg = readMsg();
		}
	}

	private String readMsg() throws IOException {
		String ans ="";
		String line = in.readLine();
		while (line != null && !line.equals("\0")){
			ans+=line+"\n";
			line =in.readLine();
		}
		int index = ans.lastIndexOf("\n");
		if (index >= 0)
		{
			ans = ans.substring(0,index);
		}
		return ans;
	}
	// Starts listening
	public void initialize() throws IOException {
		// Initialize I/O
		in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(),"UTF-8"));
		out = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream(),"UTF-8"), true);
		System.out.println("I/O initialized");
	}

	// Closes the connection
	public void close() {
		try {
			if (in != null) {
				in.close();
			}
			if (out != null) {
				Observer.observer.removeOut(out);
				System.out.println("i finshed " + out.toString());
				out.close();
			}
			clientSocket.close();
		} catch (IOException e) {
			System.out.println("Exception in closing I/O");
		}
	}
}

public class MultipleClientProtocolServer implements Runnable {
	private ServerSocket serverSocket;
	private ProtocolFactory protocolFactory;
	private int listenPort;
	private ExecutorService _executor;

	public MultipleClientProtocolServer(int port, ProtocolFactory pf) {
		_executor = Executors.newCachedThreadPool();
		serverSocket = null;
		listenPort = port;
		protocolFactory = pf;
	}

	public void run() {
		LoggerWriter logger = LoggerWriter.getLoggerWriter();
		try {
			serverSocket = new ServerSocket(listenPort);
			System.out.println("Listening...");
		} catch (IOException e) {
			logger.log("Cannot listen on port " + listenPort,Level.WARNING);
		}
		while (true) {
			try {
				ConnectionHandler2 newConnection = new ConnectionHandler2(serverSocket.accept(), protocolFactory.create());
				_executor.execute(newConnection);
			} catch (IOException e) {
				logger.log("Failed to accept on port " + listenPort,Level.WARNING);
			}
		}
	}

	// Closes the connection
	public void close() throws IOException {
		serverSocket.close();
	}
	
	public static final int port = 61614;
	public static final int webPort = 61613;
	public static void main(String[] args) throws IOException {
		// Get port
		
		ForumServer f = new ForumServer();
		MultipleClientProtocolServer server = new MultipleClientProtocolServer(port, new ForumProtocolFactory());
		MultipleClientProtocolServer webServer = new MultipleClientProtocolServer(webPort,  new ForumProtocolFactory());
		Observer.observer = new Observer();
		Thread obs = new Thread(Observer.observer);
		obs.start();
		Thread serverThread = new Thread(server);
		Thread webServerThread = new Thread(webServer);
		serverThread.start();
		webServerThread.start();
		try {
			serverThread.join();
		} catch (InterruptedException e) {
			System.out.println("Server stopped");
		}
	}
}